<!DOCTYPE html>
<html lang="zh-cn">
<head>
  
    <link type="text/css" rel="stylesheet" href="/bundles/blog-common.css?v=KOZafwuaDasEedEenI5aTy8aXH0epbm6VUJ0v3vsT_Q1"/>
<link id="MainCss" type="text/css" rel="stylesheet" href="/skins/ThinkInside/bundle-ThinkInside.css?v=RRjf6pEarGnbXZ86qxNycPfQivwSKWRa4heYLB15rVE1"/>
<link type="text/css" rel="stylesheet" href="/blog/customcss/428549.css?v=%2fam3bBTkW5NBWhBE%2fD0lcyJv5UM%3d"/>

</head>
<body>
<a name="top"></a>

<div id="page_begin_html"></div><script>load_page_begin_html();</script>

<div id="topics">
	<div class = "post">
		<h1 class = "postTitle">
			<a id="cb_post_title_url" class="postTitle2" href="https://www.cnblogs.com/frankdeng/p/9067160.html">Zookeeper（二）Zookeeper原理与API应用</a>
		</h1>
		<div class="clear"></div>
		<div class="postBody">
			<div id="cnblogs_post_body" class="blogpost-body"><h2>一 Zookeeper概述</h2>
<h3 class="topic">1.1 概述</h3>
<p class="topic">Zookeeper是Google的Chubby一个开源的实现。它是一个针对大型分布式系统的可靠协调系统，提供的功能包括：配置维护、名字服务、 分布式同步、组服务等。ZooKeeper的目标就是封装好复杂易出错的关键服务，将简单易用的接口和性能高效、功能稳定的系统提供给用户。</p>
<h3 class="topic"><img src="https://images2018.cnblogs.com/blog/1385722/201806/1385722-20180603130018358-869734209.png" alt="" /></h3>
<h3 class="topic">1.2 特点</h3>
<h3 class="topic"><img src="https://images2018.cnblogs.com/blog/1385722/201806/1385722-20180603130055896-97988805.png" alt="" /></h3>
<p class="topic">1）Zookeeper：一个领导者（leader），多个跟随者（follower）组成的集群。</p>
<p class="topic">2）Leader负责进行投票的发起和决议，更新系统状态</p>
<p class="topic">3）Follower用于接收客户请求并向客户端返回结果，在选举Leader过程中参与投票</p>
<p class="topic">4）集群中只要有半数以上节点存活，Zookeeper集群就能正常服务。</p>
<p class="topic">5）全局数据一致：每个server保存一份相同的数据副本，client无论连接到哪个server，数据都是一致的。</p>
<p class="topic">6）更新请求顺序进行，来自同一个client的更新请求按其发送顺序依次执行。</p>
<p class="topic">7）数据更新原子性，一次数据更新要么成功，要么失败。</p>
<p class="topic">8）实时性，在一定时间范围内，client能读到最新数据。</p>
<h3 class="topic">1.3 数据结构</h3>
<p class="topic"><img src="https://images2018.cnblogs.com/blog/1385722/201806/1385722-20180603130140666-679094466.png" alt="" /></p>
<p class="topic">ZooKeeper数据模型的结构与Unix文件系统很类似，整体上可以看作是一棵树，每个节点称做一个ZNode。每一个ZNode默认能够存储1MB的数据，每个ZNode都可以通过其路径唯一标识</p>
<h3 class="topic">1.4 应用场景</h3>
<p class="topic">提供的服务包括：统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等。</p>
<h3 class="topic"><img src="https://images2018.cnblogs.com/blog/1385722/201806/1385722-20180603130240963-512796102.png" alt="" /></h3>
<p><img src="https://images2018.cnblogs.com/blog/1385722/201806/1385722-20180603130321527-459615262.png" alt="" /></p>
<p><img src="https://images2018.cnblogs.com/blog/1385722/201806/1385722-20180603130402195-1150318601.png" alt="" /></p>
<p><img src="https://images2018.cnblogs.com/blog/1385722/201807/1385722-20180725222224872-1504496709.png" alt="" /></p>
<p><img src="https://images2018.cnblogs.com/blog/1385722/201807/1385722-20180725221058822-1907950541.png" alt="" /></p>
<h2>二 Zookeeper内部原理</h2>
<h3 class="topic">2.1 选举机制</h3>
<p>1<span style="font-family: 宋体;">）半数机制：集群中半数以上机器存活，集群可用。所以</span><span style="font-family: 'Times New Roman';">zookeeper</span><span style="font-family: 宋体;">适合装在奇数台机器上。</span></p>
<p>2<span style="font-family: 宋体;">）</span><span style="font-family: 'Times New Roman';">Zookeeper</span><span style="font-family: 宋体;">虽然在配置文件中并没有指定</span>master<span style="font-family: 宋体;">和</span><span style="font-family: 'Times New Roman';">slave</span><span style="font-family: 宋体;">。</span><span style="font-family: 宋体;">但是，</span>zookeeper<span style="font-family: 宋体;">工作时，是有一个节点为</span><span style="font-family: 'Times New Roman';">leader</span><span style="font-family: 宋体;">，其他则为</span><span style="font-family: 'Times New Roman';">follower</span><span style="font-family: 宋体;">，</span><span style="font-family: 'Times New Roman';">Leader</span><span style="font-family: 宋体;">是通过内部的选举机制临时产生的</span></p>
<p>3<span style="font-family: 宋体;">）以一个简单的例子来说明整个选举的过程。</span></p>
<p><span style="font-family: 宋体;">假设有五台服务器组成的</span>zookeeper<span style="font-family: 宋体;">集群，它们的</span><span style="font-family: 'Times New Roman';">id</span><span style="font-family: 宋体;">从</span><span style="font-family: 'Times New Roman';">1-5</span><span style="font-family: 宋体;">，同时它们都是最新启动的，也就是没有历史数据，在存放数据量这一点上，都是一样的。假设这些服务器依序启动，来看看会发生什么。</span></p>
<p>&nbsp;<img src="https://images2018.cnblogs.com/blog/1385722/201806/1385722-20180603131231258-1088649542.png" alt="" /></p>
<p><span style="font-family: 宋体;">（</span>1<span style="font-family: 宋体;">）服务器</span><span style="font-family: 'Times New Roman';">1</span><span style="font-family: 宋体;">启动，此时只有它一台服务器启动了，它发出去的报没有任何响应，所以它的选举状态一直是</span><span style="font-family: 'Times New Roman';">LOOKING</span><span style="font-family: 宋体;">状态。</span></p>
<p><span style="font-family: 宋体;">（</span>2<span style="font-family: 宋体;">）服务器</span><span style="font-family: 'Times New Roman';">2</span><span style="font-family: 宋体;">启动，它与最开始启动的服务器</span><span style="font-family: 'Times New Roman';">1</span><span style="font-family: 宋体;">进行通信，互相交换自己的选举结果，由于两者都没有历史数据，所以</span><span style="font-family: 'Times New Roman';">id</span><span style="font-family: 宋体;">值较大的服务器</span><span style="font-family: 'Times New Roman';">2</span><span style="font-family: 宋体;">胜出，但是由于没有达到超过半数以上的服务器都同意选举它</span><span style="font-family: 'Times New Roman';">(</span><span style="font-family: 宋体;">这个例子中的半数以上是</span><span style="font-family: 'Times New Roman';">3)</span><span style="font-family: 宋体;">，所以服务器</span><span style="font-family: 'Times New Roman';">1</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Times New Roman';">2</span><span style="font-family: 宋体;">还是继续保持</span><span style="font-family: 'Times New Roman';">LOOKING</span><span style="font-family: 宋体;">状态。</span></p>
<p><span style="font-family: 宋体;">（</span>3<span style="font-family: 宋体;">）服务器</span><span style="font-family: 'Times New Roman';">3</span><span style="font-family: 宋体;">启动，根据前面的理论分析，服务器</span><span style="font-family: 'Times New Roman';">3</span><span style="font-family: 宋体;">成为服务器</span><span style="font-family: 'Times New Roman';">1</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Times New Roman';">2</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Times New Roman';">3</span><span style="font-family: 宋体;">中的老大，而与上面不同的是，此时有三台服务器选举了它，所以它成为了这次选举的</span><span style="font-family: 'Times New Roman';">leader</span><span style="font-family: 宋体;">。</span></p>
<p><span style="font-family: 宋体;">（</span>4<span style="font-family: 宋体;">）服务器</span><span style="font-family: 'Times New Roman';">4</span><span style="font-family: 宋体;">启动，根据前面的分析，理论上服务器</span><span style="font-family: 'Times New Roman';">4</span><span style="font-family: 宋体;">应该是服务器</span><span style="font-family: 'Times New Roman';">1</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Times New Roman';">2</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Times New Roman';">3</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Times New Roman';">4</span><span style="font-family: 宋体;">中最大的，但是由于前面已经有半数以上的服务器选举了服务器</span><span style="font-family: 'Times New Roman';">3</span><span style="font-family: 宋体;">，所以它只能接收当小弟的命了。</span></p>
<p><span style="font-family: 宋体;">（</span>5<span style="font-family: 宋体;">）服务器</span><span style="font-family: 'Times New Roman';">5</span><span style="font-family: 宋体;">启动，同</span><span style="font-family: 'Times New Roman';">4</span><span style="font-family: 宋体;">一样当小弟。</span></p>
<h3 class="topic">2.2 节点类型</h3>
<p>1<span style="font-family: 宋体;">）</span><span style="font-family: 'Times New Roman';">Znode</span><span style="font-family: 宋体;">有两种类型：</span></p>
<p><span style="font-family: 宋体;">短暂（</span>ephemeral<span style="font-family: 宋体;">）：客户端</span><span style="font-family: 宋体;">和服务器端</span>断开连接后<span style="font-family: 宋体;">，创建的</span>节点自己删除</p>
<p><span style="font-family: 宋体;">持久（</span>persistent<span style="font-family: 宋体;">）：客户端</span><span style="font-family: 宋体;">和服务器端</span>断开连接后，创建的节点不删除</p>
<p>2<span style="font-family: 宋体;">）</span><span style="font-family: 'Times New Roman';">Znode</span><span style="font-family: 宋体;">有四种形式的目录节点（默认是</span><span style="font-family: 'Times New Roman';">persistent </span><span style="font-family: 宋体;">）</span></p>
<p><span style="font-family: 宋体;">（</span>1<span style="font-family: 宋体;">）</span>持久化目录节点（PERSISTENT）</p>
<p>客户端与zookeeper断开连接后，该节点依旧存在</p>
<p><span style="font-family: 宋体;">（</span>2<span style="font-family: 宋体;">）持久化顺序编号目录节点（</span>PERSISTENT_SEQUENTIAL）</p>
<p>客户端与zookeeper断开连接后，该节点依旧存在，只是Zookeeper给该节点名称进行顺序编号</p>
<p><span style="font-family: 宋体;">（</span>3<span style="font-family: 宋体;">）临时目录节点（</span>EPHEMERAL）</p>
<p>客户端与zookeeper断开连接后，该节点被删除</p>
<p><span style="font-family: 宋体;">（</span>4<span style="font-family: 宋体;">）临时顺序编号目录节点（</span>EPHEMERAL_SEQUENTIAL）</p>
<p>客户端与zookeeper断开连接后，该节点被删除，只是Zookeeper给该节点名称进行顺序编号</p>
<p><img src="https://images2018.cnblogs.com/blog/1385722/201806/1385722-20180603131319078-469987458.png" alt="" /></p>
<p>3<span style="font-family: 宋体;">）创建</span><span style="font-family: 'Times New Roman';">znode</span><span style="font-family: 宋体;">时设置顺序标识，</span><span style="font-family: 'Times New Roman';">znode</span><span style="font-family: 宋体;">名称后会附加一个值，顺序号是一个单调递增的计数器，由父节点维护</span></p>
<p>4<span style="font-family: 宋体;">）在分布式系统中，顺序号可以被用于为所有的事件进行全局排序，这样客户端可以通过顺序号推断事件的顺序</span></p>
<h3 class="topic">2.3 stat结构体</h3>
<p class="topic">1）czxid- 引起这个znode创建的zxid，创建节点的事务的zxid</p>
<p><span class="s1">每次修改ZooKeeper状态都会收到一个zxid形式的时间戳，也就是ZooKeeper事务ID。 </span></p>
<p><span class="s1">事务ID是ZooKeeper中所有修改总的次序。每个修改都有唯一的zxid，如果zxid1小于zxid2，那么zxid1在zxid2之前发生。</span></p>
<p class="topic">2）ctime - znode被创建的毫秒数(从1970年开始)</p>
<p class="topic">3）mzxid - znode最后更新的zxid</p>
<p class="topic">4）mtime - znode最后修改的毫秒数(从1970年开始)</p>
<p class="topic">5）pZxid-znode最后更新的子节点zxid</p>
<p class="topic">6）cversion - znode子节点变化号，znode子节点修改次数</p>
<p class="topic">7）dataversion - znode数据变化号</p>
<p class="topic">8）aclVersion - znode访问控制列表的变化号</p>
<p class="topic">9）ephemeralOwner- 如果是临时节点，这个是znode拥有者的session id。如果不是临时节点则是0。</p>
<p class="topic">10）dataLength- znode的数据长度</p>
<p class="topic">11）numChildren - znode子节点数量</p>
<h3 class="topic">2.4 监听器原理</h3>
<h3 class="topic"><img src="https://images2018.cnblogs.com/blog/1385722/201806/1385722-20180603131439709-1271850956.png" alt="" /></h3>
<h3 class="topic">2.5 写数据流程</h3>
<h3 class="topic"><img src="https://images2018.cnblogs.com/blog/1385722/201806/1385722-20180603131537170-1287346217.png" alt="" /></h3>
<h2 class="topic">二&nbsp;API应用</h2>
<h3 class="topic">3.1 eclipse环境搭建</h3>
<p class="topic">1）创建一个工程</p>
<p class="topic">2）解压zookeeper-3.4.12.tar.gz文件</p>
<p class="topic">3）拷贝zookeeper-3.4.12.jar、jline-0.9.94.jar、log4j-1.2.16.jar、netty-3.10.5.Final.jar、slf4j-api-1.6.1.jar、slf4j-log4j12-1.6.1.jar到工程的lib目录。并build一下，导入工程。</p>
<p class="topic">4）拷贝log4j.properties文件到项目根目录</p>
<div class="cnblogs_code">
<pre>log4j.rootLogger=<span style="color: #000000;">INFO, stdout  
log4j.appender.stdout</span>=<span style="color: #000000;">org.apache.log4j.ConsoleAppender  
log4j.appender.stdout.layout</span>=<span style="color: #000000;">org.apache.log4j.PatternLayout  
log4j.appender.stdout.layout.ConversionPattern</span>=%d %p [%c] - %m%<span style="color: #000000;">n  
log4j.appender.logfile</span>=<span style="color: #000000;">org.apache.log4j.FileAppender  
log4j.appender.logfile.File</span>=target/<span style="color: #000000;">spring.log  
log4j.appender.logfile.layout</span>=<span style="color: #000000;">org.apache.log4j.PatternLayout  
log4j.appender.logfile.layout.ConversionPattern</span>=%d %p [%c] - %m%n  </pre>
</div>
<h3 class="topic">3.2 创建ZooKeeper客户端：</h3>
<div class="notesContainer">
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> String connectString = <span style="color: #800000;">"</span><span style="color: #800000;">node21:2181,node22:2181,node23:2181</span><span style="color: #800000;">"</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">int</span> sessionTimeout = <span style="color: #800080;">2000</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">private</span> ZooKeeper zkClient = <span style="color: #0000ff;">null</span><span style="color: #000000;">;

@Before
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> init() throws Exception {
      zkClient </span>= <span style="color: #0000ff;">new</span> ZooKeeper(connectString, sessionTimeout, <span style="color: #0000ff;">new</span><span style="color: #000000;"> Watcher() {
@Override
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> process(WatchedEvent <span style="color: #0000ff;">event</span><span style="color: #000000;">) {
</span><span style="color: #008000;">      //</span><span style="color: #008000;"> 收到事件通知后的回调函数（用户的业务逻辑）</span><span style="color: #000000;">
      System.</span><span style="color: #0000ff;">out</span>.println(<span style="color: #0000ff;">event</span>.getType() + <span style="color: #800000;">"</span><span style="color: #800000;">--</span><span style="color: #800000;">"</span> + <span style="color: #0000ff;">event</span><span style="color: #000000;">.getPath());
      }
   });
}</span></pre>
</div>
</div>
<h3 class="topic">3.3 创建子节点</h3>
<div class="notesContainer">
<div class="cnblogs_code">
<pre><span style="color: #008000;">//</span><span style="color: #008000;"> 创建子节点</span><span style="color: #000000;">
@Test
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> create() throws Exception {
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 数据的增删改查
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 参数1：要创建的节点的路径； 参数2：节点数据 ； 参数3：节点权限 ；参数4：节点的类型</span>
String nodeCreated = zkClient.create(<span style="color: #800000;">"</span><span style="color: #800000;">/eclipse</span><span style="color: #800000;">"</span>, <span style="color: #800000;">"</span><span style="color: #800000;">hello zk</span><span style="color: #800000;">"</span><span style="color: #000000;">.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}</span></pre>
</div>
</div>
<h3 class="topic">3.4 获取子节点</h3>
<div class="notesContainer">
<div class="cnblogs_code">
<pre><span style="color: #008000;">//</span><span style="color: #008000;"> 获取子节点</span>
<span style="color: #000000;">@Test
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> getChildren() throws Exception {
       List</span>&lt;String&gt; children = zkClient.getChildren(<span style="color: #800000;">"</span><span style="color: #800000;">/</span><span style="color: #800000;">"</span>, <span style="color: #0000ff;">true</span><span style="color: #000000;">);
</span><span style="color: #0000ff;">       for</span><span style="color: #000000;"> (String child : children) {
              System.</span><span style="color: #0000ff;">out</span><span style="color: #000000;">.println(child);
       }
</span><span style="color: #008000;">       //</span><span style="color: #008000;"> 延时阻塞</span>
<span style="color: #000000;">       Thread.sleep(Long.MAX_VALUE);
   }</span></pre>
</div>
</div>
<h3 class="topic">3.5 判断znode是否存在</h3>
<div class="notesContainer">
<div class="cnblogs_code">
<pre><span style="color: #008000;">//</span><span style="color: #008000;"> 判断znode是否存在</span>
<span style="color: #000000;">@Test
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> exist() throws Exception {
       Stat stat </span>= zkClient.exists(<span style="color: #800000;">"</span><span style="color: #800000;">/eclipse</span><span style="color: #800000;">"</span>, <span style="color: #0000ff;">false</span><span style="color: #000000;">);
       System.</span><span style="color: #0000ff;">out</span>.println(stat == <span style="color: #0000ff;">null</span> ? <span style="color: #800000;">"</span><span style="color: #800000;">not exist</span><span style="color: #800000;">"</span> : <span style="color: #800000;">"</span><span style="color: #800000;">exist</span><span style="color: #800000;">"</span><span style="color: #000000;">);
}</span></pre>
</div>
</div>
<h2 class="topic">四 Zookeeper实战</h2>
<h3 class="topic">4.1 监听服务器节点动态上下线</h3>
<p class="topic">1）需求：某分布式系统中，主节点可以有多台，可以动态上下线，任意一台客户端都能实时感知到主节点服务器的上下线</p>
<p class="topic">2）需求分析</p>
<p class="topic"><img src="https://images2018.cnblogs.com/blog/1385722/201806/1385722-20180603132131739-212285319.png" alt="" /></p>
<p class="topic">3）具体实现：</p>
<p class="topic">（0）现在集群上创建/servers节点</p>
<div class="notesContainer">
<div class="cnblogs_code">
<pre>[zk: localhost:<span style="color: #800080;">2181</span>(CONNECTED) <span style="color: #800080;">10</span>] create /servers <span style="color: #800000;">"</span><span style="color: #800000;">servers</span><span style="color: #800000;">"</span><span style="color: #000000;">
Created </span>/servers</pre>
</div>
</div>
<h3 class="topic">（1）服务器端代码</h3>
<div class="notesContainer">
<div class="cnblogs_code">
<pre><span style="color: #000000;">package com.xyg.zkcase;

import java.io.IOException;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.ZooDefs.Ids;

</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> DistributeServer {<br />
</span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> String connectString = <span style="color: #800000;">"</span><span style="color: #800000;">node21:2181,node22:2181,node23:2181</span><span style="color: #800000;">"</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">int</span> sessionTimeout = <span style="color: #800080;">2000</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">private</span> ZooKeeper zk = <span style="color: #0000ff;">null</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">private</span> String parentNode = <span style="color: #800000;">"</span><span style="color: #800000;">/servers</span><span style="color: #800000;">"</span><span style="color: #000000;">;

</span><span style="color: #008000;">//</span><span style="color: #008000;"> 创建到zk的客户端连接</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> getConnect() throws IOException{

        zk </span>= <span style="color: #0000ff;">new</span> ZooKeeper(connectString, sessionTimeout, <span style="color: #0000ff;">new</span><span style="color: #000000;"> Watcher() {

@Override
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> process(WatchedEvent <span style="color: #0000ff;">event</span><span style="color: #000000;">) {
}
       });
}

</span><span style="color: #008000;">//</span><span style="color: #008000;"> 注册服务器</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> registServer(String hostname) throws Exception{<br />
String create </span>= zk.create(parentNode + <span style="color: #800000;">"</span><span style="color: #800000;">/server</span><span style="color: #800000;">"</span><span style="color: #000000;">, hostname.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        System.</span><span style="color: #0000ff;">out</span>.println(hostname +<span style="color: #800000;">"</span><span style="color: #800000;"> is online </span><span style="color: #800000;">"</span>+<span style="color: #000000;"> create);

}

</span><span style="color: #008000;">//</span><span style="color: #008000;"> 业务功能</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> business(String hostname) throws Exception{

       System.</span><span style="color: #0000ff;">out</span>.println(hostname+<span style="color: #800000;">"</span><span style="color: #800000;"> is working ...</span><span style="color: #800000;">"</span><span style="color: #000000;">);
       Thread.sleep(Long.MAX_VALUE);
}

</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) throws Exception {
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 获取zk连接</span><span style="color: #000000;">
DistributeServer server </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> DistributeServer();
server.getConnect();
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 利用zk连接注册服务器信息</span><span style="color: #000000;">
server.registServer(args[</span><span style="color: #800080;">0</span><span style="color: #000000;">]);
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 启动业务功能</span><span style="color: #000000;">
server.business(args[</span><span style="color: #800080;">0</span><span style="color: #000000;">]);
 }
}</span></pre>
</div>
</div>
<h3 class="topic">（2）客户端代码</h3>
<div class="notesContainer">
<div class="cnblogs_code">
<pre><span style="color: #000000;">package com.xyg.zkcase;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;

</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> DistributeClient {
</span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> String connectString = <span style="color: #800000;">"</span><span style="color: #800000;">hadoop102:2181,hadoop103:2181,hadoop104:2181</span><span style="color: #800000;">"</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">int</span> sessionTimeout = <span style="color: #800080;">2000</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">private</span> ZooKeeper zk = <span style="color: #0000ff;">null</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">private</span> String parentNode = <span style="color: #800000;">"</span><span style="color: #800000;">/servers</span><span style="color: #800000;">"</span><span style="color: #000000;">;

</span><span style="color: #008000;">//</span><span style="color: #008000;"> 创建到zk的客户端连接</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> getConnect() throws IOException {
      zk </span>= <span style="color: #0000ff;">new</span> ZooKeeper(connectString, sessionTimeout, <span style="color: #0000ff;">new</span><span style="color: #000000;"> Watcher() {

@Override
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> process(WatchedEvent <span style="color: #0000ff;">event</span><span style="color: #000000;">) {
</span><span style="color: #008000;">      //</span><span style="color: #008000;"> 再次启动监听</span>
<span style="color: #0000ff;">      try</span><span style="color: #000000;"> {
          getServerList();
          } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e) {
            e.printStackTrace();
          }
      }
   });
}
</span><span style="color: #008000;">//</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> getServerList() throws Exception {

</span><span style="color: #008000;">    //</span><span style="color: #008000;"> 获取服务器子节点信息，并且对父节点进行监听</span><span style="color: #000000;">
    List</span>&lt;String&gt; children = zk.getChildren(parentNode, <span style="color: #0000ff;">true</span><span style="color: #000000;">);
    ArrayList</span>&lt;String&gt; servers = <span style="color: #0000ff;">new</span> ArrayList&lt;&gt;<span style="color: #000000;">();
</span><span style="color: #0000ff;">    for</span><span style="color: #000000;"> (String child : children) {
</span><span style="color: #0000ff;">    byte</span>[] data = zk.getData(parentNode + <span style="color: #800000;">"</span><span style="color: #800000;">/</span><span style="color: #800000;">"</span> + child, <span style="color: #0000ff;">false</span>, <span style="color: #0000ff;">null</span><span style="color: #000000;">);
    servers.add(</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> String(data));
}
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 把servers赋值给成员serverList，已提供给各业务线程使用</span><span style="color: #000000;">
     serversList </span>=<span style="color: #000000;"> servers;
     System.</span><span style="color: #0000ff;">out</span><span style="color: #000000;">.println(serversList);
}
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 业务功能</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> business() throws Exception {
       System.</span><span style="color: #0000ff;">out</span>.println(<span style="color: #800000;">"</span><span style="color: #800000;">client is working ...</span><span style="color: #800000;">"</span><span style="color: #000000;">);
}<br />
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) throws Exception {

</span><span style="color: #008000;">//</span><span style="color: #008000;"> 获取zk连接</span><span style="color: #000000;">
DistributeClient client </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> DistributeClient();
client.getConnect();
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 获取servers的子节点信息，从中获取服务器信息列表</span><span style="color: #000000;">
client.getServerList();
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 业务进程启动</span><span style="color: #000000;">
client.business();
}
}</span></pre>
</div>

</body>
</html>
